/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	XMLElement.cpp
*
*	Comments	-	See XMLElement.h
*
**************************************************************************************/
#include "../Include/XMLElement.h"
#include "../Include/XMLDocument.h"

namespace Pulse
{
	XMLElement::XMLElement( XMLDocument *pDoc, tinyxml2::XMLElement *pElem )
		: m_pDoc( pDoc ), m_pElem(pElem)
	{
	}

	XMLElement::~XMLElement( void )
	{
	}

	BOOL XMLElement::IsValid( void ) const
	{
		return m_pElem != PSX_NULL;
	}

	String XMLElement::GetAttribute( const CHAR *pAttribute ) const
	{
		Char buffer[250];
		String::ToMultiByte( pAttribute, buffer, 250 );

		return  m_pElem->Attribute( buffer );
	}

	String XMLElement::GetAttribute( const Char *pAttribute ) const
	{
		return m_pElem->Attribute(pAttribute);
	}

	String XMLElement::GetName( void ) const
	{
		return m_pElem->Value();
	}

	String XMLElement::GetValue( void ) const
	{
		return m_pElem->GetText();
	}

	const Char * XMLElement::GetValueRaw( void ) const
	{
		return m_pElem->GetText();
	}

	XMLElementPtr XMLElement::GetNextSibling( void ) const
	{
		tinyxml2::XMLElement *pNode = m_pElem->NextSiblingElement();
		
		if ( pNode )
			return new XMLElement( m_pDoc, pNode );
		else
			return PSX_NULL;
	}

	XMLElementPtr XMLElement::GetFirstChild( void ) const
	{
		tinyxml2::XMLElement *pNode = m_pElem->FirstChildElement();

		if ( pNode )
			return new XMLElement( m_pDoc, pNode );
		else 
			return PSX_NULL;
	}

	XMLElementPtr XMLElement::GetParent( void ) const
	{
		return new XMLElement( m_pDoc, m_pElem->Parent()->ToElement() );
	}

	void XMLElement::SetName( const CHAR *pName )
	{
		Char buffer[250];
		String::ToMultiByte( pName, buffer, 250 );

		m_pElem->SetName( buffer );
	}

	void XMLElement::SetValue( const CHAR *pValue )
	{
		// TODO: Remove any text children frist...

		SIZE_T len = PSX_StrLen(pValue) + 1; // include string terminator
		Char *pBuffer = new Char[len];
		String::ToMultiByte( pValue, pBuffer, len );
		m_pElem->InsertEndChild( m_pDoc->m_pDoc->NewText( pBuffer ) );
		delete [] pBuffer;
	}

	void XMLElement::AddValue( const CHAR *pValue )
	{
		SIZE_T len = PSX_StrLen(pValue) + 1; // include string terminator
		Char *pBuffer = new Char[len];
		String::ToMultiByte( pValue, pBuffer, len );
		m_pElem->InsertEndChild( m_pDoc->m_pDoc->NewText( pBuffer ) );
		delete [] pBuffer;
	}

	void XMLElement::SetAttribute( const CHAR *pName, const CHAR *pValue )
	{
		Char buffer1[250], buffer2[250];
		String::ToMultiByte( pName, buffer1, 250 );
		String::ToMultiByte( pValue, buffer2, 250 );
		m_pElem->SetAttribute( buffer1, buffer2 );
	}

	void XMLElement::SetAttribute( const CHAR *pName, const INT value )
	{
		Char buffer[250];
		String::ToMultiByte( pName, buffer, 250 );
		m_pElem->SetAttribute( buffer, value );
	}

	void XMLElement::SetAttribute( const CHAR *pName, const UINT value )
	{
		Char buffer[250];
		String::ToMultiByte( pName, buffer, 250 );
		m_pElem->SetAttribute( buffer, value );
	}

	void XMLElement::SetAttribute( const CHAR *pName, const BOOL value )
	{
		Char buffer[250];
		String::ToMultiByte( pName, buffer, 250 );
		m_pElem->SetAttribute( buffer, value );
	}

	void XMLElement::SetAttribute( const CHAR *pName, const DOUBLE value )
	{
		Char buffer[250];
		String::ToMultiByte( pName, buffer, 250 );
		m_pElem->SetAttribute( buffer, value );
	}

	XMLElementPtr XMLElement::CreateChild( const CHAR *pName )
	{
		XMLElementPtr pChild = m_pDoc->CreateElement( pName );
		AddChild( pChild->m_pElem );
		return pChild;
	}

	void XMLElement::AttachChild( XMLElementPtr pElem )
	{
		AddChild( pElem->m_pElem );
	}

	BOOL XMLElement::RemoveChild( const CHAR *pName )
	{
		Char buffer[256];
		String::ToMultiByte( pName, buffer, 256 );
		XMLElementPtr pElem = FindChild( pName );
		
		if ( pElem.IsNull() )
			return FALSE;
		
		m_pElem->DeleteChild( pElem->m_pElem );
		return TRUE;
	}

	XMLElementPtr XMLElement::FindChild( const CHAR *pName )
	{
		String name;
		tinyxml2::XMLElement *pElem = m_pElem->FirstChildElement();

		while ( pElem )
		{
			name = pElem->Value();

			if ( name == pName )
				return new XMLElement( m_pDoc, pElem );

			pElem = pElem->NextSiblingElement();
		}

		return PSX_NULL;
	}

	void XMLElement::ClearChildren( void )
	{
		m_pElem->DeleteChildren();
	}

	void XMLElement::AddChild( tinyxml2::XMLElement *pElement )
	{
		// TODO: Check if element already exists
		const char *pName = pElement->Value();
		m_pElem->InsertEndChild( pElement );
	}

}